nanopyx._version
Git implementation of _version.py.
1# This file helps to compute a version number in source trees obtained from 2# git-archive tarball (such as those provided by githubs download-from-tag 3# feature). Distribution tarballs (built by setup.py sdist) and build 4# directories (produced by setup.py build) will contain a much shorter file 5# that just contains the computed version number. 6 7# This file is released into the public domain. 8# Generated by versioneer-0.28 9# https://github.com/python-versioneer/python-versioneer 10 11"""Git implementation of _version.py.""" 12 13import errno 14import os 15import re 16import subprocess 17import sys 18from typing import Callable, Dict 19import functools 20 21 22def get_keywords(): 23 """Get the keywords needed to look up the version information.""" 24 # these strings will be replaced by git during git-archive. 25 # setup.py/versioneer.py will grep for the variable names, so they must 26 # each be defined on a line of their own. _version.py will just call 27 # get_keywords(). 28 git_refnames = "$Format:%d$" 29 git_full = "$Format:%H$" 30 git_date = "$Format:%ci$" 31 keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} 32 return keywords 33 34 35class VersioneerConfig: 36 """Container for Versioneer configuration parameters.""" 37 38 39def get_config(): 40 """Create, populate and return the VersioneerConfig() object.""" 41 # these strings are filled in when 'setup.py versioneer' creates 42 # _version.py 43 cfg = VersioneerConfig() 44 cfg.VCS = "git" 45 cfg.style = "pep440" 46 cfg.tag_prefix = "" 47 cfg.parentdir_prefix = "nanopyx-" 48 cfg.versionfile_source = "src/nanopyx/_version.py" 49 cfg.verbose = False 50 return cfg 51 52 53class NotThisMethod(Exception): 54 """Exception raised if a method is not valid for the current scenario.""" 55 56 57LONG_VERSION_PY: Dict[str, str] = {} 58HANDLERS: Dict[str, Dict[str, Callable]] = {} 59 60 61def register_vcs_handler(vcs, method): # decorator 62 """Create decorator to mark a method as the handler of a VCS.""" 63 64 def decorate(f): 65 """Store f in HANDLERS[vcs][method].""" 66 if vcs not in HANDLERS: 67 HANDLERS[vcs] = {} 68 HANDLERS[vcs][method] = f 69 return f 70 71 return decorate 72 73 74def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): 75 """Call the given command(s).""" 76 assert isinstance(commands, list) 77 process = None 78 79 popen_kwargs = {} 80 if sys.platform == "win32": 81 # This hides the console window if pythonw.exe is used 82 startupinfo = subprocess.STARTUPINFO() 83 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 84 popen_kwargs["startupinfo"] = startupinfo 85 86 for command in commands: 87 try: 88 dispcmd = str([command] + args) 89 # remember shell=False, so use git.cmd on windows, not just git 90 process = subprocess.Popen( 91 [command] + args, 92 cwd=cwd, 93 env=env, 94 stdout=subprocess.PIPE, 95 stderr=(subprocess.PIPE if hide_stderr else None), 96 **popen_kwargs, 97 ) 98 break 99 except OSError: 100 e = sys.exc_info()[1] 101 if e.errno == errno.ENOENT: 102 continue 103 if verbose: 104 print("unable to run %s" % dispcmd) 105 print(e) 106 return None, None 107 else: 108 if verbose: 109 print("unable to find command, tried %s" % (commands,)) 110 return None, None 111 stdout = process.communicate()[0].strip().decode() 112 if process.returncode != 0: 113 if verbose: 114 print("unable to run %s (error)" % dispcmd) 115 print("stdout was %s" % stdout) 116 return None, process.returncode 117 return stdout, process.returncode 118 119 120def versions_from_parentdir(parentdir_prefix, root, verbose): 121 """Try to determine the version from the parent directory name. 122 123 Source tarballs conventionally unpack into a directory that includes both 124 the project name and a version string. We will also support searching up 125 two directory levels for an appropriately named parent directory 126 """ 127 rootdirs = [] 128 129 for _ in range(3): 130 dirname = os.path.basename(root) 131 if dirname.startswith(parentdir_prefix): 132 return { 133 "version": dirname[len(parentdir_prefix) :], 134 "full-revisionid": None, 135 "dirty": False, 136 "error": None, 137 "date": None, 138 } 139 rootdirs.append(root) 140 root = os.path.dirname(root) # up a level 141 142 if verbose: 143 print( 144 "Tried directories %s but none started with prefix %s" 145 % (str(rootdirs), parentdir_prefix) 146 ) 147 raise NotThisMethod("rootdir doesn't start with parentdir_prefix") 148 149 150@register_vcs_handler("git", "get_keywords") 151def git_get_keywords(versionfile_abs): 152 """Extract version information from the given file.""" 153 # the code embedded in _version.py can just fetch the value of these 154 # keywords. When used from setup.py, we don't want to import _version.py, 155 # so we do it with a regexp instead. This function is not used from 156 # _version.py. 157 keywords = {} 158 try: 159 with open(versionfile_abs, "r") as fobj: 160 for line in fobj: 161 if line.strip().startswith("git_refnames ="): 162 mo = re.search(r'=\s*"(.*)"', line) 163 if mo: 164 keywords["refnames"] = mo.group(1) 165 if line.strip().startswith("git_full ="): 166 mo = re.search(r'=\s*"(.*)"', line) 167 if mo: 168 keywords["full"] = mo.group(1) 169 if line.strip().startswith("git_date ="): 170 mo = re.search(r'=\s*"(.*)"', line) 171 if mo: 172 keywords["date"] = mo.group(1) 173 except OSError: 174 pass 175 return keywords 176 177 178@register_vcs_handler("git", "keywords") 179def git_versions_from_keywords(keywords, tag_prefix, verbose): 180 """Get version information from git keywords.""" 181 if "refnames" not in keywords: 182 raise NotThisMethod("Short version file found") 183 date = keywords.get("date") 184 if date is not None: 185 # Use only the last line. Previous lines may contain GPG signature 186 # information. 187 date = date.splitlines()[-1] 188 189 # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant 190 # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 191 # -like" string, which we must then edit to make compliant), because 192 # it's been around since git-1.5.3, and it's too difficult to 193 # discover which version we're using, or to work around using an 194 # older one. 195 date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 196 refnames = keywords["refnames"].strip() 197 if refnames.startswith("$Format"): 198 if verbose: 199 print("keywords are unexpanded, not using") 200 raise NotThisMethod("unexpanded keywords, not a git-archive tarball") 201 refs = {r.strip() for r in refnames.strip("()").split(",")} 202 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of 203 # just "foo-1.0". If we see a "tag: " prefix, prefer those. 204 TAG = "tag: " 205 tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} 206 if not tags: 207 # Either we're using git < 1.8.3, or there really are no tags. We use 208 # a heuristic: assume all version tags have a digit. The old git %d 209 # expansion behaves like git log --decorate=short and strips out the 210 # refs/heads/ and refs/tags/ prefixes that would let us distinguish 211 # between branches and tags. By ignoring refnames without digits, we 212 # filter out many common branch names like "release" and 213 # "stabilization", as well as "HEAD" and "master". 214 tags = {r for r in refs if re.search(r"\d", r)} 215 if verbose: 216 print("discarding '%s', no digits" % ",".join(refs - tags)) 217 if verbose: 218 print("likely tags: %s" % ",".join(sorted(tags))) 219 for ref in sorted(tags): 220 # sorting will prefer e.g. "2.0" over "2.0rc1" 221 if ref.startswith(tag_prefix): 222 r = ref[len(tag_prefix) :] 223 # Filter out refs that exactly match prefix or that don't start 224 # with a number once the prefix is stripped (mostly a concern 225 # when prefix is '') 226 if not re.match(r"\d", r): 227 continue 228 if verbose: 229 print("picking %s" % r) 230 return { 231 "version": r, 232 "full-revisionid": keywords["full"].strip(), 233 "dirty": False, 234 "error": None, 235 "date": date, 236 } 237 # no suitable tags, so version is "0+unknown", but full hex is still there 238 if verbose: 239 print("no suitable tags, using unknown + full revision id") 240 return { 241 "version": "0+unknown", 242 "full-revisionid": keywords["full"].strip(), 243 "dirty": False, 244 "error": "no suitable tags", 245 "date": None, 246 } 247 248 249@register_vcs_handler("git", "pieces_from_vcs") 250def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): 251 """Get version from 'git describe' in the root of the source tree. 252 253 This only gets called if the git-archive 'subst' keywords were *not* 254 expanded, and _version.py hasn't already been rewritten with a short 255 version string, meaning we're inside a checked out source tree. 256 """ 257 GITS = ["git"] 258 if sys.platform == "win32": 259 GITS = ["git.cmd", "git.exe"] 260 261 # GIT_DIR can interfere with correct operation of Versioneer. 262 # It may be intended to be passed to the Versioneer-versioned project, 263 # but that should not change where we get our version from. 264 env = os.environ.copy() 265 env.pop("GIT_DIR", None) 266 runner = functools.partial(runner, env=env) 267 268 _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) 269 if rc != 0: 270 if verbose: 271 print("Directory %s not under git control" % root) 272 raise NotThisMethod("'git rev-parse --git-dir' returned error") 273 274 # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] 275 # if there isn't one, this yields HEX[-dirty] (no NUM) 276 describe_out, rc = runner( 277 GITS, 278 [ 279 "describe", 280 "--tags", 281 "--dirty", 282 "--always", 283 "--long", 284 "--match", 285 f"{tag_prefix}[[:digit:]]*", 286 ], 287 cwd=root, 288 ) 289 # --long was added in git-1.5.5 290 if describe_out is None: 291 raise NotThisMethod("'git describe' failed") 292 describe_out = describe_out.strip() 293 full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) 294 if full_out is None: 295 raise NotThisMethod("'git rev-parse' failed") 296 full_out = full_out.strip() 297 298 pieces = {} 299 pieces["long"] = full_out 300 pieces["short"] = full_out[:7] # maybe improved later 301 pieces["error"] = None 302 303 branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) 304 # --abbrev-ref was added in git-1.6.3 305 if rc != 0 or branch_name is None: 306 raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") 307 branch_name = branch_name.strip() 308 309 if branch_name == "HEAD": 310 # If we aren't exactly on a branch, pick a branch which represents 311 # the current commit. If all else fails, we are on a branchless 312 # commit. 313 branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) 314 # --contains was added in git-1.5.4 315 if rc != 0 or branches is None: 316 raise NotThisMethod("'git branch --contains' returned error") 317 branches = branches.split("\n") 318 319 # Remove the first line if we're running detached 320 if "(" in branches[0]: 321 branches.pop(0) 322 323 # Strip off the leading "* " from the list of branches. 324 branches = [branch[2:] for branch in branches] 325 if "master" in branches: 326 branch_name = "master" 327 elif not branches: 328 branch_name = None 329 else: 330 # Pick the first branch that is returned. Good or bad. 331 branch_name = branches[0] 332 333 pieces["branch"] = branch_name 334 335 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] 336 # TAG might have hyphens. 337 git_describe = describe_out 338 339 # look for -dirty suffix 340 dirty = git_describe.endswith("-dirty") 341 pieces["dirty"] = dirty 342 if dirty: 343 git_describe = git_describe[: git_describe.rindex("-dirty")] 344 345 # now we have TAG-NUM-gHEX or HEX 346 347 if "-" in git_describe: 348 # TAG-NUM-gHEX 349 mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) 350 if not mo: 351 # unparsable. Maybe git-describe is misbehaving? 352 pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out 353 return pieces 354 355 # tag 356 full_tag = mo.group(1) 357 if not full_tag.startswith(tag_prefix): 358 if verbose: 359 fmt = "tag '%s' doesn't start with prefix '%s'" 360 print(fmt % (full_tag, tag_prefix)) 361 pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( 362 full_tag, 363 tag_prefix, 364 ) 365 return pieces 366 pieces["closest-tag"] = full_tag[len(tag_prefix) :] 367 368 # distance: number of commits since tag 369 pieces["distance"] = int(mo.group(2)) 370 371 # commit: short hex revision ID 372 pieces["short"] = mo.group(3) 373 374 else: 375 # HEX: no tags 376 pieces["closest-tag"] = None 377 out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) 378 pieces["distance"] = len(out.split()) # total number of commits 379 380 # commit date: see ISO-8601 comment in git_versions_from_keywords() 381 date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() 382 # Use only the last line. Previous lines may contain GPG signature 383 # information. 384 date = date.splitlines()[-1] 385 pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 386 387 return pieces 388 389 390def plus_or_dot(pieces): 391 """Return a + if we don't already have one, else return a .""" 392 if "+" in pieces.get("closest-tag", ""): 393 return "." 394 return "+" 395 396 397def render_pep440(pieces): 398 """Build up version string, with post-release "local version identifier". 399 400 Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you 401 get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty 402 403 Exceptions: 404 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] 405 """ 406 if pieces["closest-tag"]: 407 rendered = pieces["closest-tag"] 408 if pieces["distance"] or pieces["dirty"]: 409 rendered += plus_or_dot(pieces) 410 rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 411 if pieces["dirty"]: 412 rendered += ".dirty" 413 else: 414 # exception #1 415 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) 416 if pieces["dirty"]: 417 rendered += ".dirty" 418 return rendered 419 420 421def render_pep440_branch(pieces): 422 """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . 423 424 The ".dev0" means not master branch. Note that .dev0 sorts backwards 425 (a feature branch will appear "older" than the master branch). 426 427 Exceptions: 428 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] 429 """ 430 if pieces["closest-tag"]: 431 rendered = pieces["closest-tag"] 432 if pieces["distance"] or pieces["dirty"]: 433 if pieces["branch"] != "master": 434 rendered += ".dev0" 435 rendered += plus_or_dot(pieces) 436 rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 437 if pieces["dirty"]: 438 rendered += ".dirty" 439 else: 440 # exception #1 441 rendered = "0" 442 if pieces["branch"] != "master": 443 rendered += ".dev0" 444 rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) 445 if pieces["dirty"]: 446 rendered += ".dirty" 447 return rendered 448 449 450def pep440_split_post(ver): 451 """Split pep440 version string at the post-release segment. 452 453 Returns the release segments before the post-release and the 454 post-release version number (or -1 if no post-release segment is present). 455 """ 456 vc = str.split(ver, ".post") 457 return vc[0], int(vc[1] or 0) if len(vc) == 2 else None 458 459 460def render_pep440_pre(pieces): 461 """TAG[.postN.devDISTANCE] -- No -dirty. 462 463 Exceptions: 464 1: no tags. 0.post0.devDISTANCE 465 """ 466 if pieces["closest-tag"]: 467 if pieces["distance"]: 468 # update the post release segment 469 tag_version, post_version = pep440_split_post(pieces["closest-tag"]) 470 rendered = tag_version 471 if post_version is not None: 472 rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) 473 else: 474 rendered += ".post0.dev%d" % (pieces["distance"]) 475 else: 476 # no commits, use the tag as the version 477 rendered = pieces["closest-tag"] 478 else: 479 # exception #1 480 rendered = "0.post0.dev%d" % pieces["distance"] 481 return rendered 482 483 484def render_pep440_post(pieces): 485 """TAG[.postDISTANCE[.dev0]+gHEX] . 486 487 The ".dev0" means dirty. Note that .dev0 sorts backwards 488 (a dirty tree will appear "older" than the corresponding clean one), 489 but you shouldn't be releasing software with -dirty anyways. 490 491 Exceptions: 492 1: no tags. 0.postDISTANCE[.dev0] 493 """ 494 if pieces["closest-tag"]: 495 rendered = pieces["closest-tag"] 496 if pieces["distance"] or pieces["dirty"]: 497 rendered += ".post%d" % pieces["distance"] 498 if pieces["dirty"]: 499 rendered += ".dev0" 500 rendered += plus_or_dot(pieces) 501 rendered += "g%s" % pieces["short"] 502 else: 503 # exception #1 504 rendered = "0.post%d" % pieces["distance"] 505 if pieces["dirty"]: 506 rendered += ".dev0" 507 rendered += "+g%s" % pieces["short"] 508 return rendered 509 510 511def render_pep440_post_branch(pieces): 512 """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . 513 514 The ".dev0" means not master branch. 515 516 Exceptions: 517 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] 518 """ 519 if pieces["closest-tag"]: 520 rendered = pieces["closest-tag"] 521 if pieces["distance"] or pieces["dirty"]: 522 rendered += ".post%d" % pieces["distance"] 523 if pieces["branch"] != "master": 524 rendered += ".dev0" 525 rendered += plus_or_dot(pieces) 526 rendered += "g%s" % pieces["short"] 527 if pieces["dirty"]: 528 rendered += ".dirty" 529 else: 530 # exception #1 531 rendered = "0.post%d" % pieces["distance"] 532 if pieces["branch"] != "master": 533 rendered += ".dev0" 534 rendered += "+g%s" % pieces["short"] 535 if pieces["dirty"]: 536 rendered += ".dirty" 537 return rendered 538 539 540def render_pep440_old(pieces): 541 """TAG[.postDISTANCE[.dev0]] . 542 543 The ".dev0" means dirty. 544 545 Exceptions: 546 1: no tags. 0.postDISTANCE[.dev0] 547 """ 548 if pieces["closest-tag"]: 549 rendered = pieces["closest-tag"] 550 if pieces["distance"] or pieces["dirty"]: 551 rendered += ".post%d" % pieces["distance"] 552 if pieces["dirty"]: 553 rendered += ".dev0" 554 else: 555 # exception #1 556 rendered = "0.post%d" % pieces["distance"] 557 if pieces["dirty"]: 558 rendered += ".dev0" 559 return rendered 560 561 562def render_git_describe(pieces): 563 """TAG[-DISTANCE-gHEX][-dirty]. 564 565 Like 'git describe --tags --dirty --always'. 566 567 Exceptions: 568 1: no tags. HEX[-dirty] (note: no 'g' prefix) 569 """ 570 if pieces["closest-tag"]: 571 rendered = pieces["closest-tag"] 572 if pieces["distance"]: 573 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 574 else: 575 # exception #1 576 rendered = pieces["short"] 577 if pieces["dirty"]: 578 rendered += "-dirty" 579 return rendered 580 581 582def render_git_describe_long(pieces): 583 """TAG-DISTANCE-gHEX[-dirty]. 584 585 Like 'git describe --tags --dirty --always -long'. 586 The distance/hash is unconditional. 587 588 Exceptions: 589 1: no tags. HEX[-dirty] (note: no 'g' prefix) 590 """ 591 if pieces["closest-tag"]: 592 rendered = pieces["closest-tag"] 593 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 594 else: 595 # exception #1 596 rendered = pieces["short"] 597 if pieces["dirty"]: 598 rendered += "-dirty" 599 return rendered 600 601 602def render(pieces, style): 603 """Render the given version pieces into the requested style.""" 604 if pieces["error"]: 605 return { 606 "version": "unknown", 607 "full-revisionid": pieces.get("long"), 608 "dirty": None, 609 "error": pieces["error"], 610 "date": None, 611 } 612 613 if not style or style == "default": 614 style = "pep440" # the default 615 616 if style == "pep440": 617 rendered = render_pep440(pieces) 618 elif style == "pep440-branch": 619 rendered = render_pep440_branch(pieces) 620 elif style == "pep440-pre": 621 rendered = render_pep440_pre(pieces) 622 elif style == "pep440-post": 623 rendered = render_pep440_post(pieces) 624 elif style == "pep440-post-branch": 625 rendered = render_pep440_post_branch(pieces) 626 elif style == "pep440-old": 627 rendered = render_pep440_old(pieces) 628 elif style == "git-describe": 629 rendered = render_git_describe(pieces) 630 elif style == "git-describe-long": 631 rendered = render_git_describe_long(pieces) 632 else: 633 raise ValueError("unknown style '%s'" % style) 634 635 return { 636 "version": rendered, 637 "full-revisionid": pieces["long"], 638 "dirty": pieces["dirty"], 639 "error": None, 640 "date": pieces.get("date"), 641 } 642 643 644def get_versions(): 645 """Get version information or return default if unable to do so.""" 646 # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have 647 # __file__, we can work backwards from there to the root. Some 648 # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which 649 # case we can only use expanded keywords. 650 651 cfg = get_config() 652 verbose = cfg.verbose 653 654 try: 655 return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) 656 except NotThisMethod: 657 pass 658 659 try: 660 root = os.path.realpath(__file__) 661 # versionfile_source is the relative path from the top of the source 662 # tree (where the .git directory might live) to this file. Invert 663 # this to find the root from __file__. 664 for _ in cfg.versionfile_source.split("/"): 665 root = os.path.dirname(root) 666 except NameError: 667 return { 668 "version": "0+unknown", 669 "full-revisionid": None, 670 "dirty": None, 671 "error": "unable to find root of source tree", 672 "date": None, 673 } 674 675 try: 676 pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) 677 return render(pieces, cfg.style) 678 except NotThisMethod: 679 pass 680 681 try: 682 if cfg.parentdir_prefix: 683 return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) 684 except NotThisMethod: 685 pass 686 687 return { 688 "version": "0+unknown", 689 "full-revisionid": None, 690 "dirty": None, 691 "error": "unable to compute version", 692 "date": None, 693 }
23def get_keywords(): 24 """Get the keywords needed to look up the version information.""" 25 # these strings will be replaced by git during git-archive. 26 # setup.py/versioneer.py will grep for the variable names, so they must 27 # each be defined on a line of their own. _version.py will just call 28 # get_keywords(). 29 git_refnames = "$Format:%d$" 30 git_full = "$Format:%H$" 31 git_date = "$Format:%ci$" 32 keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} 33 return keywords
Get the keywords needed to look up the version information.
Container for Versioneer configuration parameters.
40def get_config(): 41 """Create, populate and return the VersioneerConfig() object.""" 42 # these strings are filled in when 'setup.py versioneer' creates 43 # _version.py 44 cfg = VersioneerConfig() 45 cfg.VCS = "git" 46 cfg.style = "pep440" 47 cfg.tag_prefix = "" 48 cfg.parentdir_prefix = "nanopyx-" 49 cfg.versionfile_source = "src/nanopyx/_version.py" 50 cfg.verbose = False 51 return cfg
Create, populate and return the VersioneerConfig() object.
54class NotThisMethod(Exception): 55 """Exception raised if a method is not valid for the current scenario."""
Exception raised if a method is not valid for the current scenario.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
62def register_vcs_handler(vcs, method): # decorator 63 """Create decorator to mark a method as the handler of a VCS.""" 64 65 def decorate(f): 66 """Store f in HANDLERS[vcs][method].""" 67 if vcs not in HANDLERS: 68 HANDLERS[vcs] = {} 69 HANDLERS[vcs][method] = f 70 return f 71 72 return decorate
Create decorator to mark a method as the handler of a VCS.
75def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): 76 """Call the given command(s).""" 77 assert isinstance(commands, list) 78 process = None 79 80 popen_kwargs = {} 81 if sys.platform == "win32": 82 # This hides the console window if pythonw.exe is used 83 startupinfo = subprocess.STARTUPINFO() 84 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 85 popen_kwargs["startupinfo"] = startupinfo 86 87 for command in commands: 88 try: 89 dispcmd = str([command] + args) 90 # remember shell=False, so use git.cmd on windows, not just git 91 process = subprocess.Popen( 92 [command] + args, 93 cwd=cwd, 94 env=env, 95 stdout=subprocess.PIPE, 96 stderr=(subprocess.PIPE if hide_stderr else None), 97 **popen_kwargs, 98 ) 99 break 100 except OSError: 101 e = sys.exc_info()[1] 102 if e.errno == errno.ENOENT: 103 continue 104 if verbose: 105 print("unable to run %s" % dispcmd) 106 print(e) 107 return None, None 108 else: 109 if verbose: 110 print("unable to find command, tried %s" % (commands,)) 111 return None, None 112 stdout = process.communicate()[0].strip().decode() 113 if process.returncode != 0: 114 if verbose: 115 print("unable to run %s (error)" % dispcmd) 116 print("stdout was %s" % stdout) 117 return None, process.returncode 118 return stdout, process.returncode
Call the given command(s).
121def versions_from_parentdir(parentdir_prefix, root, verbose): 122 """Try to determine the version from the parent directory name. 123 124 Source tarballs conventionally unpack into a directory that includes both 125 the project name and a version string. We will also support searching up 126 two directory levels for an appropriately named parent directory 127 """ 128 rootdirs = [] 129 130 for _ in range(3): 131 dirname = os.path.basename(root) 132 if dirname.startswith(parentdir_prefix): 133 return { 134 "version": dirname[len(parentdir_prefix) :], 135 "full-revisionid": None, 136 "dirty": False, 137 "error": None, 138 "date": None, 139 } 140 rootdirs.append(root) 141 root = os.path.dirname(root) # up a level 142 143 if verbose: 144 print( 145 "Tried directories %s but none started with prefix %s" 146 % (str(rootdirs), parentdir_prefix) 147 ) 148 raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
Try to determine the version from the parent directory name.
Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory
151@register_vcs_handler("git", "get_keywords") 152def git_get_keywords(versionfile_abs): 153 """Extract version information from the given file.""" 154 # the code embedded in _version.py can just fetch the value of these 155 # keywords. When used from setup.py, we don't want to import _version.py, 156 # so we do it with a regexp instead. This function is not used from 157 # _version.py. 158 keywords = {} 159 try: 160 with open(versionfile_abs, "r") as fobj: 161 for line in fobj: 162 if line.strip().startswith("git_refnames ="): 163 mo = re.search(r'=\s*"(.*)"', line) 164 if mo: 165 keywords["refnames"] = mo.group(1) 166 if line.strip().startswith("git_full ="): 167 mo = re.search(r'=\s*"(.*)"', line) 168 if mo: 169 keywords["full"] = mo.group(1) 170 if line.strip().startswith("git_date ="): 171 mo = re.search(r'=\s*"(.*)"', line) 172 if mo: 173 keywords["date"] = mo.group(1) 174 except OSError: 175 pass 176 return keywords
Extract version information from the given file.
179@register_vcs_handler("git", "keywords") 180def git_versions_from_keywords(keywords, tag_prefix, verbose): 181 """Get version information from git keywords.""" 182 if "refnames" not in keywords: 183 raise NotThisMethod("Short version file found") 184 date = keywords.get("date") 185 if date is not None: 186 # Use only the last line. Previous lines may contain GPG signature 187 # information. 188 date = date.splitlines()[-1] 189 190 # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant 191 # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 192 # -like" string, which we must then edit to make compliant), because 193 # it's been around since git-1.5.3, and it's too difficult to 194 # discover which version we're using, or to work around using an 195 # older one. 196 date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 197 refnames = keywords["refnames"].strip() 198 if refnames.startswith("$Format"): 199 if verbose: 200 print("keywords are unexpanded, not using") 201 raise NotThisMethod("unexpanded keywords, not a git-archive tarball") 202 refs = {r.strip() for r in refnames.strip("()").split(",")} 203 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of 204 # just "foo-1.0". If we see a "tag: " prefix, prefer those. 205 TAG = "tag: " 206 tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} 207 if not tags: 208 # Either we're using git < 1.8.3, or there really are no tags. We use 209 # a heuristic: assume all version tags have a digit. The old git %d 210 # expansion behaves like git log --decorate=short and strips out the 211 # refs/heads/ and refs/tags/ prefixes that would let us distinguish 212 # between branches and tags. By ignoring refnames without digits, we 213 # filter out many common branch names like "release" and 214 # "stabilization", as well as "HEAD" and "master". 215 tags = {r for r in refs if re.search(r"\d", r)} 216 if verbose: 217 print("discarding '%s', no digits" % ",".join(refs - tags)) 218 if verbose: 219 print("likely tags: %s" % ",".join(sorted(tags))) 220 for ref in sorted(tags): 221 # sorting will prefer e.g. "2.0" over "2.0rc1" 222 if ref.startswith(tag_prefix): 223 r = ref[len(tag_prefix) :] 224 # Filter out refs that exactly match prefix or that don't start 225 # with a number once the prefix is stripped (mostly a concern 226 # when prefix is '') 227 if not re.match(r"\d", r): 228 continue 229 if verbose: 230 print("picking %s" % r) 231 return { 232 "version": r, 233 "full-revisionid": keywords["full"].strip(), 234 "dirty": False, 235 "error": None, 236 "date": date, 237 } 238 # no suitable tags, so version is "0+unknown", but full hex is still there 239 if verbose: 240 print("no suitable tags, using unknown + full revision id") 241 return { 242 "version": "0+unknown", 243 "full-revisionid": keywords["full"].strip(), 244 "dirty": False, 245 "error": "no suitable tags", 246 "date": None, 247 }
Get version information from git keywords.
250@register_vcs_handler("git", "pieces_from_vcs") 251def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): 252 """Get version from 'git describe' in the root of the source tree. 253 254 This only gets called if the git-archive 'subst' keywords were *not* 255 expanded, and _version.py hasn't already been rewritten with a short 256 version string, meaning we're inside a checked out source tree. 257 """ 258 GITS = ["git"] 259 if sys.platform == "win32": 260 GITS = ["git.cmd", "git.exe"] 261 262 # GIT_DIR can interfere with correct operation of Versioneer. 263 # It may be intended to be passed to the Versioneer-versioned project, 264 # but that should not change where we get our version from. 265 env = os.environ.copy() 266 env.pop("GIT_DIR", None) 267 runner = functools.partial(runner, env=env) 268 269 _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) 270 if rc != 0: 271 if verbose: 272 print("Directory %s not under git control" % root) 273 raise NotThisMethod("'git rev-parse --git-dir' returned error") 274 275 # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] 276 # if there isn't one, this yields HEX[-dirty] (no NUM) 277 describe_out, rc = runner( 278 GITS, 279 [ 280 "describe", 281 "--tags", 282 "--dirty", 283 "--always", 284 "--long", 285 "--match", 286 f"{tag_prefix}[[:digit:]]*", 287 ], 288 cwd=root, 289 ) 290 # --long was added in git-1.5.5 291 if describe_out is None: 292 raise NotThisMethod("'git describe' failed") 293 describe_out = describe_out.strip() 294 full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) 295 if full_out is None: 296 raise NotThisMethod("'git rev-parse' failed") 297 full_out = full_out.strip() 298 299 pieces = {} 300 pieces["long"] = full_out 301 pieces["short"] = full_out[:7] # maybe improved later 302 pieces["error"] = None 303 304 branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) 305 # --abbrev-ref was added in git-1.6.3 306 if rc != 0 or branch_name is None: 307 raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") 308 branch_name = branch_name.strip() 309 310 if branch_name == "HEAD": 311 # If we aren't exactly on a branch, pick a branch which represents 312 # the current commit. If all else fails, we are on a branchless 313 # commit. 314 branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) 315 # --contains was added in git-1.5.4 316 if rc != 0 or branches is None: 317 raise NotThisMethod("'git branch --contains' returned error") 318 branches = branches.split("\n") 319 320 # Remove the first line if we're running detached 321 if "(" in branches[0]: 322 branches.pop(0) 323 324 # Strip off the leading "* " from the list of branches. 325 branches = [branch[2:] for branch in branches] 326 if "master" in branches: 327 branch_name = "master" 328 elif not branches: 329 branch_name = None 330 else: 331 # Pick the first branch that is returned. Good or bad. 332 branch_name = branches[0] 333 334 pieces["branch"] = branch_name 335 336 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] 337 # TAG might have hyphens. 338 git_describe = describe_out 339 340 # look for -dirty suffix 341 dirty = git_describe.endswith("-dirty") 342 pieces["dirty"] = dirty 343 if dirty: 344 git_describe = git_describe[: git_describe.rindex("-dirty")] 345 346 # now we have TAG-NUM-gHEX or HEX 347 348 if "-" in git_describe: 349 # TAG-NUM-gHEX 350 mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) 351 if not mo: 352 # unparsable. Maybe git-describe is misbehaving? 353 pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out 354 return pieces 355 356 # tag 357 full_tag = mo.group(1) 358 if not full_tag.startswith(tag_prefix): 359 if verbose: 360 fmt = "tag '%s' doesn't start with prefix '%s'" 361 print(fmt % (full_tag, tag_prefix)) 362 pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( 363 full_tag, 364 tag_prefix, 365 ) 366 return pieces 367 pieces["closest-tag"] = full_tag[len(tag_prefix) :] 368 369 # distance: number of commits since tag 370 pieces["distance"] = int(mo.group(2)) 371 372 # commit: short hex revision ID 373 pieces["short"] = mo.group(3) 374 375 else: 376 # HEX: no tags 377 pieces["closest-tag"] = None 378 out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) 379 pieces["distance"] = len(out.split()) # total number of commits 380 381 # commit date: see ISO-8601 comment in git_versions_from_keywords() 382 date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() 383 # Use only the last line. Previous lines may contain GPG signature 384 # information. 385 date = date.splitlines()[-1] 386 pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 387 388 return pieces
Get version from 'git describe' in the root of the source tree.
This only gets called if the git-archive 'subst' keywords were not expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree.
391def plus_or_dot(pieces): 392 """Return a + if we don't already have one, else return a .""" 393 if "+" in pieces.get("closest-tag", ""): 394 return "." 395 return "+"
Return a + if we don't already have one, else return a .
398def render_pep440(pieces): 399 """Build up version string, with post-release "local version identifier". 400 401 Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you 402 get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty 403 404 Exceptions: 405 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] 406 """ 407 if pieces["closest-tag"]: 408 rendered = pieces["closest-tag"] 409 if pieces["distance"] or pieces["dirty"]: 410 rendered += plus_or_dot(pieces) 411 rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 412 if pieces["dirty"]: 413 rendered += ".dirty" 414 else: 415 # exception #1 416 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) 417 if pieces["dirty"]: 418 rendered += ".dirty" 419 return rendered
Build up version string, with post-release "local version identifier".
Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
422def render_pep440_branch(pieces): 423 """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . 424 425 The ".dev0" means not master branch. Note that .dev0 sorts backwards 426 (a feature branch will appear "older" than the master branch). 427 428 Exceptions: 429 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] 430 """ 431 if pieces["closest-tag"]: 432 rendered = pieces["closest-tag"] 433 if pieces["distance"] or pieces["dirty"]: 434 if pieces["branch"] != "master": 435 rendered += ".dev0" 436 rendered += plus_or_dot(pieces) 437 rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 438 if pieces["dirty"]: 439 rendered += ".dirty" 440 else: 441 # exception #1 442 rendered = "0" 443 if pieces["branch"] != "master": 444 rendered += ".dev0" 445 rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) 446 if pieces["dirty"]: 447 rendered += ".dirty" 448 return rendered
TAG[[.dev0]+DISTANCE.gHEX[.dirty]] .
The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch).
Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty]
451def pep440_split_post(ver): 452 """Split pep440 version string at the post-release segment. 453 454 Returns the release segments before the post-release and the 455 post-release version number (or -1 if no post-release segment is present). 456 """ 457 vc = str.split(ver, ".post") 458 return vc[0], int(vc[1] or 0) if len(vc) == 2 else None
Split pep440 version string at the post-release segment.
Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present).
461def render_pep440_pre(pieces): 462 """TAG[.postN.devDISTANCE] -- No -dirty. 463 464 Exceptions: 465 1: no tags. 0.post0.devDISTANCE 466 """ 467 if pieces["closest-tag"]: 468 if pieces["distance"]: 469 # update the post release segment 470 tag_version, post_version = pep440_split_post(pieces["closest-tag"]) 471 rendered = tag_version 472 if post_version is not None: 473 rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) 474 else: 475 rendered += ".post0.dev%d" % (pieces["distance"]) 476 else: 477 # no commits, use the tag as the version 478 rendered = pieces["closest-tag"] 479 else: 480 # exception #1 481 rendered = "0.post0.dev%d" % pieces["distance"] 482 return rendered
TAG[.postN.devDISTANCE] -- No -dirty.
Exceptions: 1: no tags. 0.post0.devDISTANCE
485def render_pep440_post(pieces): 486 """TAG[.postDISTANCE[.dev0]+gHEX] . 487 488 The ".dev0" means dirty. Note that .dev0 sorts backwards 489 (a dirty tree will appear "older" than the corresponding clean one), 490 but you shouldn't be releasing software with -dirty anyways. 491 492 Exceptions: 493 1: no tags. 0.postDISTANCE[.dev0] 494 """ 495 if pieces["closest-tag"]: 496 rendered = pieces["closest-tag"] 497 if pieces["distance"] or pieces["dirty"]: 498 rendered += ".post%d" % pieces["distance"] 499 if pieces["dirty"]: 500 rendered += ".dev0" 501 rendered += plus_or_dot(pieces) 502 rendered += "g%s" % pieces["short"] 503 else: 504 # exception #1 505 rendered = "0.post%d" % pieces["distance"] 506 if pieces["dirty"]: 507 rendered += ".dev0" 508 rendered += "+g%s" % pieces["short"] 509 return rendered
TAG[.postDISTANCE[.dev0]+gHEX] .
The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways.
Exceptions: 1: no tags. 0.postDISTANCE[.dev0]
512def render_pep440_post_branch(pieces): 513 """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . 514 515 The ".dev0" means not master branch. 516 517 Exceptions: 518 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] 519 """ 520 if pieces["closest-tag"]: 521 rendered = pieces["closest-tag"] 522 if pieces["distance"] or pieces["dirty"]: 523 rendered += ".post%d" % pieces["distance"] 524 if pieces["branch"] != "master": 525 rendered += ".dev0" 526 rendered += plus_or_dot(pieces) 527 rendered += "g%s" % pieces["short"] 528 if pieces["dirty"]: 529 rendered += ".dirty" 530 else: 531 # exception #1 532 rendered = "0.post%d" % pieces["distance"] 533 if pieces["branch"] != "master": 534 rendered += ".dev0" 535 rendered += "+g%s" % pieces["short"] 536 if pieces["dirty"]: 537 rendered += ".dirty" 538 return rendered
TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] .
The ".dev0" means not master branch.
Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty]
541def render_pep440_old(pieces): 542 """TAG[.postDISTANCE[.dev0]] . 543 544 The ".dev0" means dirty. 545 546 Exceptions: 547 1: no tags. 0.postDISTANCE[.dev0] 548 """ 549 if pieces["closest-tag"]: 550 rendered = pieces["closest-tag"] 551 if pieces["distance"] or pieces["dirty"]: 552 rendered += ".post%d" % pieces["distance"] 553 if pieces["dirty"]: 554 rendered += ".dev0" 555 else: 556 # exception #1 557 rendered = "0.post%d" % pieces["distance"] 558 if pieces["dirty"]: 559 rendered += ".dev0" 560 return rendered
TAG[.postDISTANCE[.dev0]] .
The ".dev0" means dirty.
Exceptions: 1: no tags. 0.postDISTANCE[.dev0]
563def render_git_describe(pieces): 564 """TAG[-DISTANCE-gHEX][-dirty]. 565 566 Like 'git describe --tags --dirty --always'. 567 568 Exceptions: 569 1: no tags. HEX[-dirty] (note: no 'g' prefix) 570 """ 571 if pieces["closest-tag"]: 572 rendered = pieces["closest-tag"] 573 if pieces["distance"]: 574 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 575 else: 576 # exception #1 577 rendered = pieces["short"] 578 if pieces["dirty"]: 579 rendered += "-dirty" 580 return rendered
TAG[-DISTANCE-gHEX][-dirty].
Like 'git describe --tags --dirty --always'.
Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix)
583def render_git_describe_long(pieces): 584 """TAG-DISTANCE-gHEX[-dirty]. 585 586 Like 'git describe --tags --dirty --always -long'. 587 The distance/hash is unconditional. 588 589 Exceptions: 590 1: no tags. HEX[-dirty] (note: no 'g' prefix) 591 """ 592 if pieces["closest-tag"]: 593 rendered = pieces["closest-tag"] 594 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 595 else: 596 # exception #1 597 rendered = pieces["short"] 598 if pieces["dirty"]: 599 rendered += "-dirty" 600 return rendered
TAG-DISTANCE-gHEX[-dirty].
Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional.
Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix)
603def render(pieces, style): 604 """Render the given version pieces into the requested style.""" 605 if pieces["error"]: 606 return { 607 "version": "unknown", 608 "full-revisionid": pieces.get("long"), 609 "dirty": None, 610 "error": pieces["error"], 611 "date": None, 612 } 613 614 if not style or style == "default": 615 style = "pep440" # the default 616 617 if style == "pep440": 618 rendered = render_pep440(pieces) 619 elif style == "pep440-branch": 620 rendered = render_pep440_branch(pieces) 621 elif style == "pep440-pre": 622 rendered = render_pep440_pre(pieces) 623 elif style == "pep440-post": 624 rendered = render_pep440_post(pieces) 625 elif style == "pep440-post-branch": 626 rendered = render_pep440_post_branch(pieces) 627 elif style == "pep440-old": 628 rendered = render_pep440_old(pieces) 629 elif style == "git-describe": 630 rendered = render_git_describe(pieces) 631 elif style == "git-describe-long": 632 rendered = render_git_describe_long(pieces) 633 else: 634 raise ValueError("unknown style '%s'" % style) 635 636 return { 637 "version": rendered, 638 "full-revisionid": pieces["long"], 639 "dirty": pieces["dirty"], 640 "error": None, 641 "date": pieces.get("date"), 642 }
Render the given version pieces into the requested style.
645def get_versions(): 646 """Get version information or return default if unable to do so.""" 647 # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have 648 # __file__, we can work backwards from there to the root. Some 649 # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which 650 # case we can only use expanded keywords. 651 652 cfg = get_config() 653 verbose = cfg.verbose 654 655 try: 656 return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) 657 except NotThisMethod: 658 pass 659 660 try: 661 root = os.path.realpath(__file__) 662 # versionfile_source is the relative path from the top of the source 663 # tree (where the .git directory might live) to this file. Invert 664 # this to find the root from __file__. 665 for _ in cfg.versionfile_source.split("/"): 666 root = os.path.dirname(root) 667 except NameError: 668 return { 669 "version": "0+unknown", 670 "full-revisionid": None, 671 "dirty": None, 672 "error": "unable to find root of source tree", 673 "date": None, 674 } 675 676 try: 677 pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) 678 return render(pieces, cfg.style) 679 except NotThisMethod: 680 pass 681 682 try: 683 if cfg.parentdir_prefix: 684 return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) 685 except NotThisMethod: 686 pass 687 688 return { 689 "version": "0+unknown", 690 "full-revisionid": None, 691 "dirty": None, 692 "error": "unable to compute version", 693 "date": None, 694 }
Get version information or return default if unable to do so.